/*
	   _           _      _           _     _ 
	  (_)         | |    | |         (_)   | |
	   _ _   _ ___| |_ __| |_ __ ___  _  __| |
	  | | | | / __| __/ _` | '__/ _ \| |/ _` |
	  | | |_| \__ \ || (_| | | | (_) | | (_| |
	  | |\__,_|___/\__\__,_|_|  \___/|_|\__,_|
	 _/ |                                     
	|__/ 
	
	Copyright 2013 Caspar Isemer and and Eva Krueger, http://justdroid.org
	
	Licensed under the Apache License, Version 2.0 (the "License");
	you may not use this file except in compliance with the License.
	You may obtain a copy of the License at
	
		http://www.apache.org/licenses/LICENSE-2.0
	
	Unless required by applicable law or agreed to in writing, software
	distributed under the License is distributed on an "AS IS" BASIS,
	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
	See the License for the specific language governing permissions and
	limitations under the License. 
*/

package org.justdroid.justdroid;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;

import android.annotation.SuppressLint;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.Html;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnKeyListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.Toast;

public class TextMessagesApp extends JustDroidActivity implements OnClickListener{
	private Button btnInbox, btnSent, btnCompose;
	private ListView messageListView;
	private Runnable runnable;
	private Cursor cursor;
	private Handler handler;
	private CommonAdapter adapter;
	private ArrayList<HashMap<String, String>> records;
	private ArrayList<String> numbers;
	private int currentSelection = -1;
	private static final int SWIPE_MIN_DISTANCE = 120;
    private static final int SWIPE_MAX_OFF_PATH = 250;
    private static final int SWIPE_THRESHOLD_VELOCITY = 200;
    private GestureDetector gestureDetector;
	View.OnTouchListener gestureListener;
	
	private final static int INBOX = 1;
	private final static int SENT = 2;
	private int typeOfMessage, i, oldPosition;

	void loadInboxMessages() {
		TextMessagesApp.this.typeOfMessage = INBOX;
    	if(TextMessagesApp.this.cursor != null) {
    		TextMessagesApp.this.cursor.close();
    		TextMessagesApp.this.cursor = null;
    	}
    	//if(TextMessagesApp.this.cursor != null) {
    		//TextMessagesApp.this.cursor.moveToFirst();
			 //refresh the list
		runThread(TextMessagesApp.this.typeOfMessage);
		//}
	}
	
	void loadSentMessages() {
		TextMessagesApp.this.typeOfMessage = SENT;
    	if(TextMessagesApp.this.cursor != null) {
    		TextMessagesApp.this.cursor.close();
    		TextMessagesApp.this.cursor = null;
    	}
    	runThread(TextMessagesApp.this.typeOfMessage);
	}
	
	void compose() {
		Intent intent = new Intent(getApplicationContext(), TextMessagesComposerRecipientApp.class);
		startActivity(intent);
	}
	
	void startNewActivity(String number) {
		Intent intent = new Intent(getApplicationContext(), TextMessagesViewerApp.class);
		intent.putExtra("address", number);
		startActivity(intent);
	}
	
	void attachKeyListener(final Button button, final int buttonFlag) {
		button.setOnKeyListener(new OnKeyListener() {
			
			@Override
			public boolean onKey(View view, int keyCode, KeyEvent keyEvent) {
				if(keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
					switch(keyCode) {
					case KeyEvent.KEYCODE_DPAD_CENTER:
					case KeyEvent.KEYCODE_ENTER:
						switch(buttonFlag) {
						case 1:
							loadInboxMessages();
							break;
						case 2:
							loadSentMessages();
							break;
						case 3:
							compose();
							break;
						}
						break;
					}
				}
				return false;
			}
		});
	}
	
	/** Function to execute a thread to retrieve dialed call logs **/
	void runThread(final int typeOfMessage) {
		runnable = new Runnable() {
			@Override
			public void run() {
				getMessages(typeOfMessage);
			}
		};
		new Thread(runnable).start();
	}
	
	/** Function to retrieve messages **/
	@SuppressLint("SimpleDateFormat")
	void getMessages(int typeOfMessage) {
		Bundle senderDetails;
		Message message = new Message();
		Bundle bundle = new Bundle();
		String uri = "";
		TextMessagesApp.this.numbers = new ArrayList<String>();
		switch(typeOfMessage) {
			case INBOX: uri = "content://sms/inbox";
				break;
			case SENT: uri = "content://sms/sent";
				break;
		}
			if(this.cursor == null) {
				this.cursor = getContentResolver().query(Uri.parse(uri),  new String[]{"DISTINCT address", "date", "read", "subject", "body"}, 
						"address IS NOT NULL) GROUP BY (address", null, null);
				if(this.cursor.getCount() > 0) {
					this.cursor.moveToFirst();
					TextMessagesApp.this.records = new ArrayList<HashMap<String,String>>();
				}
			}
			else {
				if(this.cursor.getPosition() != 0)
				this.cursor.moveToNext();
			}
			if(this.cursor.getCount() > 0 && this.cursor.getPosition() < this.cursor.getCount()) {
				i = 0;
				do{
					senderDetails = new Bundle();
					senderDetails.putString("address", this.cursor.getString(this.cursor.getColumnIndex("address")));
					
					TextMessagesApp.this.numbers.add(senderDetails.getString("address"));
					
					Date date = new Date(Long.valueOf(this.cursor.getString(this.cursor.getColumnIndex("date"))));
					SimpleDateFormat simpleDateFormat = new SimpleDateFormat("d MMMM yyyy' 'HH:MM:ss");
					senderDetails.putString("date", Html.fromHtml("<br/>") + simpleDateFormat.format(date) + " ");
					senderDetails.putString("read", cursor.getString(this.cursor.getColumnIndex("read")));
					senderDetails.putString("subject", this.cursor.getString(this.cursor.getColumnIndex("subject")));
					senderDetails.putString("body", this.cursor.getString(this.cursor.getColumnIndex("body")));
					bundle.putBundle(Integer.toString(i), senderDetails);
					i++;
				}while(i<5 && this.cursor.moveToNext() && this.cursor.getPosition() < this.cursor.getCount());
				message.setData(bundle);
			}
		handler.sendMessage(message);
	}
	
	/** Create the Text Messages activity **/
	@SuppressLint("HandlerLeak")
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		setContentView(R.layout.textmessages);
		super.onCreate(savedInstanceState);
		
		// Currently, do not know how to write the code that implements lateral navigation to swipe via tabs
		// as described at http://developer.android.com/training/implementing-navigation/lateral.html,
		// since swiping has already been implemented for the home screens
		
		/** Find UI elements **/
		btnInbox = (Button) findViewById(R.id.tabTextMsgsInbox);
		btnSent = (Button) findViewById(R.id.tabTextMsgsSent);
		btnCompose = (Button) findViewById(R.id.tabTextMsgsWrite);
		
		messageListView = (ListView) findViewById(R.id.lstMessages);
		/*TextView txtTextMsgsEntry2 = (TextView) findViewById(R.id.txtTextMsgsEntry2);
		TextView txtTextMsgsEntry3 = (TextView) findViewById(R.id.txtTextMsgsEntry3);
		TextView txtTextMsgsEntry4 = (TextView) findViewById(R.id.txtTextMsgsEntry4);
		TextView txtTextMsgsEntry5 = (TextView) findViewById(R.id.txtTextMsgsEntry5);*/
	    
		attachListener(btnInbox);
		attachListener(btnSent);
		attachListener(btnCompose);
		
		this.records = new ArrayList<HashMap<String, String>>();
		this.numbers = new ArrayList<String>();
		this.cursor = null;
		this.typeOfMessage = INBOX;
		this.oldPosition = 0;
		
		 //load the list
		runThread(this.typeOfMessage);
		 // Gesture detection
        gestureDetector = new GestureDetector(this, new MyGestureDetector());
        gestureListener = new View.OnTouchListener() {
            public boolean onTouch(View v, MotionEvent event) {
                return gestureDetector.onTouchEvent(event);
            }
        };
        
        messageListView.setOnKeyListener(new OnKeyListener() {
			
			@Override
			public boolean onKey(View view, int keyCode, KeyEvent keyEvent) {
				ListView lstView = (ListView) view;
				if(keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
					switch(keyCode) {
					case KeyEvent.KEYCODE_DPAD_CENTER:
						startNewActivity(TextMessagesApp.this.numbers.get(currentSelection));
						break;
					case KeyEvent.KEYCODE_DPAD_DOWN:
						currentSelection++;
						if(currentSelection == lstView.getCount()) {
							currentSelection = 0;
						}
						lstView.setSelection(currentSelection);
						break;
					}
				}
				return false;
			}
		});
        
        messageListView.setOnTouchListener(gestureListener);
        
/*        messageListView.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> arg0, View view, int position,
					long arg3) {
				//vibrate
				Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
			    vibrator.vibrate(200);
			    String textToSpeak = adapter.getItem(position).toString(); 
			    if(textToSpeak.equals("read"))
			    	textToSpeak = "red";
				TTS.speak(textToSpeak);
			}			
		});
  */      
        messageListView.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> arg0, View view,
					int position, long arg3) {
				startNewActivity(TextMessagesApp.this.numbers.get(position));
			}
		});
		
        attachKeyListener(btnInbox, 1);
		/** If Inbox tab is pressed, bring up the text messages inbox **/
		btnInbox.setOnClickListener(new View.OnClickListener() {
	        public void onClick(View v) {
	        	loadInboxMessages();
	        }
	    });
		
		attachKeyListener(btnSent, 2);
		/** If Sent tab is pressed, bring up the sent text messages **/
		btnSent.setOnClickListener(new View.OnClickListener() {
	        public void onClick(View v) {
	        	loadSentMessages();
	        }
	    });		
		
		attachKeyListener(btnCompose, 3);
		/** If Write tab is pressed, launch the justdroid Text Messages Composer app **/
		btnCompose.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				compose();
			}
		});
		
		/** If some text message entry is pressed, display it in the justdroid Text Message Viewer app **/
	//	setTextviewClickAppClass(R.id.txtTextMsgsEntry1, TextMessagesApp.this, TextMessagesViewerApp.class);
		
		/** If some text message entry is pressed, display it in the justdroid Text Message Viewer app **/
		/*txtTextMsgsEntry2.setOnClickListener(new View.OnClickListener() {
	        public void onClick(View v) {
	        	Context context = getApplicationContext();
	        	CharSequence text = "Clicking on an entry would display the text message.";
	        	Toast.makeText(context, text, Toast.LENGTH_LONG).show();
	        }
	    });*/		
		
		/** If some text message entry is pressed, display it in the justdroid Text Message Viewer app **/
		/*txtTextMsgsEntry3.setOnClickListener(new View.OnClickListener() {
	        public void onClick(View v) {
	        	Context context = getApplicationContext();
	        	CharSequence text = "Clicking on an entry would display the text message.";
	        	Toast.makeText(context, text, Toast.LENGTH_LONG).show();
	        }
	    });*/		
		
		/** If some text message entry is pressed, display it in the justdroid Text Message Viewer app **/
		/*txtTextMsgsEntry4.setOnClickListener(new View.OnClickListener() {
	        public void onClick(View v) {
	        	Context context = getApplicationContext();
	        	CharSequence text = "Clicking on an entry would display the text message.";
	        	Toast.makeText(context, text, Toast.LENGTH_LONG).show();
	        }
	    });*/	
		
		/** If some text message entry is pressed, display it in the justdroid Text Message Viewer app **/
	/*	txtTextMsgsEntry5.setOnClickListener(new View.OnClickListener() {
	        public void onClick(View v) {
	        	Context context = getApplicationContext();
	        	CharSequence text = "Clicking on an entry would display the text message.";
	        	Toast.makeText(context, text, Toast.LENGTH_LONG).show();
	        }
	    });*/		
		
		
		handler = new Handler() {
			@Override
			public void handleMessage(Message message) {
				ArrayList<String> strRecords = new ArrayList<String>();
				HashMap<String, String> record;
				Bundle bundle = message.getData();
				if(bundle.size() < 1) {
					//empty messages
					if(Utils.isAccessibilityEnabled(getApplicationContext()))
						TTS.speak(getResources().getString(R.string.emptymessages));
					Toast.makeText(getApplicationContext(), getResources().getString(R.string.emptymessages), Toast.LENGTH_SHORT).show();
				}
				else {
						for(int i=0; i<bundle.size(); i++) {
								Bundle tempBundle = bundle.getBundle(Integer.toString(i));
								record = new HashMap<String, String>();
								String read = getResources().getString(R.string.unread), subject = " ";
								//address, date, read, subject, body
								if(TextMessagesApp.this.typeOfMessage != SENT) { //sent messages are always read
									if(tempBundle.getString("read").equals("1")) {
										record.put("read", "1");
										read = getResources().getString(R.string.read);
									}
									else {
										record.put("read", "0");
									}
								}
								else {
									read = "";
								}
								if(tempBundle.getString("subject") != null) {
									subject = tempBundle.getString("subject");
									record.put("subject", subject);
								}
								else {
									record.put("subject", "");
								}
								HashMap<String, String> map = (new ContactManager(getApplicationContext()).getNameFromNumber(tempBundle.getString("address")));
								if(map.size() == 1) {
									//number does not correspond to a name
									strRecords.add(tempBundle.getString("address") + " " + tempBundle.getString("date") + subject + read);
								}
								else {
									record.put("name", tempBundle.getString("name"));
									strRecords.add(map.get("name") + " " + map.get("type") + " " + tempBundle.getString("date") + subject + read);
								}
								record.put("number", tempBundle.getString("address"));
								record.put("date", tempBundle.getString("date"));
								record.put("read", tempBundle.getString("read"));
								record.put("subject", tempBundle.getString("subject"));
								record.put("body", tempBundle.getString("body"));
								TextMessagesApp.this.records.add(record);
							}
				}				
				adapter = new CommonAdapter(getApplicationContext(), strRecords);
				messageListView.setAdapter(adapter);
				messageListView.setVisibility(View.VISIBLE);
			}
		};
		/** Put most everything before here **/
	}	
	
	@Override
	public void onResume() {
		super.onResume();
		if(this.cursor != null) {
			this.cursor.moveToFirst();
			 //refresh the list
			runThread(INBOX);
		}
		//get the root layout
		LinearLayout layout = (LinearLayout) findViewById(R.id.textmessages);
		//get the values in SharedPreferences
		Utils.applyFontColorChanges(getApplicationContext(), layout);  Utils.applyFontSizeChanges(getApplicationContext(), layout);  Utils.applyFontTypeChanges(getApplicationContext(), layout);
	}
	
	
	class MyGestureDetector extends SimpleOnGestureListener {
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            try {
                if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
                    return false;
                // right to left swipe
                if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                   //get next 5 messages
                	if(TextMessagesApp.this.cursor.getPosition() == TextMessagesApp.this.cursor.getCount()) {
                		if(Utils.isAccessibilityEnabled(getApplicationContext()))
                			giveFeedback(getResources().getString(R.string.reachedEnd));
                		Toast.makeText(getApplicationContext(), getResources().getString(R.string.reachedEnd), Toast.LENGTH_SHORT).show();
                	}
                	else {
                		if(Utils.isAccessibilityEnabled(getApplicationContext()))
                			giveFeedback(getResources().getString(R.string.next));
                		Toast.makeText(getApplicationContext(), getResources().getString(R.string.next), Toast.LENGTH_SHORT).show();
                		runThread(TextMessagesApp.this.typeOfMessage);
                	}
                }  else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                    //get previous 5 messages
                	int positionDifference = ((5+i)==10)?10:(5+i+1); 
                	TextMessagesApp.this.cursor.moveToPosition(TextMessagesApp.this.cursor.getPosition() - positionDifference);	
                	if((TextMessagesApp.this.cursor.getPosition() <= -1) && oldPosition <= -1) {
                		if(Utils.isAccessibilityEnabled(getApplicationContext()))
                			giveFeedback(getResources().getString(R.string.reachedBeginning));
                		Toast.makeText(getApplicationContext(), getResources().getString(R.string.reachedBeginning), Toast.LENGTH_SHORT).show();	
                	}
                	else {
                		if(Utils.isAccessibilityEnabled(getApplicationContext()))
                			giveFeedback(getResources().getString(R.string.previous));
                		Toast.makeText(getApplicationContext(), getResources().getString(R.string.previous), Toast.LENGTH_SHORT).show();	
                		runThread(TextMessagesApp.this.typeOfMessage);
                	}
                	oldPosition = TextMessagesApp.this.cursor.getPosition();
                }
            } catch (Exception e) {
                // nothing
            }
            return false;
        }

            @Override
        public boolean onDown(MotionEvent e) {
              return false;
        }
            
    }


	@Override
	public void onClick(View view) {
		// TODO Auto-generated method stub
		
	}
}
